package reflex.layouts
{
	
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import reflex.binding.DataChange;
	import reflex.measurement.IMeasurablePercent;
	import reflex.measurement.calculateAvailableSpace;
	import reflex.measurement.calculatePercentageTotals;
	import reflex.measurement.resolveHeight;
	import reflex.measurement.resolveWidth;
	import reflex.measurement.setSize;
	import reflex.styles.resolveStyle;
	
	[LayoutProperty(name="width", measure="true")]
	[LayoutProperty(name="height", measure="true")]
	
	/**
	 * Provides a measured layout from top to bottom.
	 * 
	 * @alpha
	 **/
	public class VerticalLayout extends Layout implements ILayout
	{		
		private var _gap:Number = 0;
		[Bindable("gapChange")]
		public function get gap():Number{return _gap;}
		public function set gap(value:Number):void{
			DataChange.change(this, "gap", _gap, _gap = value)
		}
		
		private var _verticalAlign:String;
		[Bindable("verticalAlignChange")]
		[Inspectable(type=String, defaultValue="top", enumeration="top,middle,center,bottom")]
		public function get verticalAlign():String{return _verticalAlign;}		
		public function set verticalAlign(value:String):void{
			DataChange.change(this, "verticalAlign", _verticalAlign, _verticalAlign = value)
		}
		
		private var _horizontalAlign:String;
		[Bindable("horizontalAlignChange")]
		[Inspectable(type=String, defaultValue="left", enumeration="left,middle,center,right")]
		public function get horizontalAlign():String{return _horizontalAlign;}
		public function set horizontalAlign(value:String):void{
			DataChange.change(this, "horizontalAlign", _horizontalAlign, _horizontalAlign = value)
		}
		
		private var _paddingLeft:Number = 0;
		[Bindable("paddingLeftChange")]
		public function get paddingLeft():Number{return _paddingLeft;}
		public function set paddingLeft(value:Number):void{
			DataChange.change(this, "paddingLeft", _paddingLeft, _paddingLeft = value)
		}
		
		private var _paddingRight:Number = 0;
		[Bindable("paddingRightChange")]
		public function get paddingRight():Number{return _paddingRight;}
		public function set paddingRight(value:Number):void{
			DataChange.change(this, "paddingRight", _paddingRight, _paddingRight = value)
		}
		
		private var _paddingTop:Number = 0;
		[Bindable("paddingTopChange")]
		public function get paddingTop():Number{return _paddingTop;}
		public function set paddingTop(value:Number):void{
			DataChange.change(this, "paddingTop", _paddingTop, _paddingTop = value)
		}
		
		private var _paddingBottom:Number = 0;
		[Bindable("paddingBottomChange")]
		public function get paddingBottom():Number{return _paddingBottom;}
		public function set paddingBottom(value:Number):void{
			DataChange.change(this, "paddingBottom", _paddingBottom, _paddingBottom = value)
		}
		
		public function VerticalLayout(gap:Number = 5, horizontalAlign:String = "left", verticalAlign:String="top"):void {
			super();
			this.gap = gap;
			this.horizontalAlign = horizontalAlign;
			this.verticalAlign = verticalAlign;
		}
		
		override public function measure(children:Array):Point
		{
			var point:Point = super.measure(children);
			point.x = point.y = 0
			for each(var child:Object in children) {
				var width:Number = reflex.measurement.resolveWidth(child);
				var height:Number = reflex.measurement.resolveHeight(child);
				point.x = Math.max(point.x, width);
				point.y += height + gap;
			}
			if (children)
				point.y -= gap;
			point.x += paddingLeft + paddingRight
			point.y += paddingTop + paddingRight
			return point;
		}
		
		override public function update(children:Array, rectangle:Rectangle):void
		{
			super.update(children, rectangle);
			if(children) {
				
				// some style-binding might take care of this later
				var gap:Number = reflex.styles.resolveStyle(target, "gap", Number, this.gap) as Number;
				var verticalAlign:String = reflex.styles.resolveStyle(target, "verticalAlign", String, this.verticalAlign) as String;
				var horizontalAlign:String = reflex.styles.resolveStyle(target, "horizontalAlign", String, this.horizontalAlign) as String;
				var paddingTop:Number = reflex.styles.resolveStyle(target, "paddingTop", Number, this.paddingTop) as Number;
				var paddingBottom:Number = reflex.styles.resolveStyle(target, "paddingBottom", Number, this.paddingBottom) as Number;
				var paddingLeft:Number = reflex.styles.resolveStyle(target, "paddingLeft", Number, this.paddingLeft) as Number;
				var paddingRight:Number = reflex.styles.resolveStyle(target, "paddingRight", Number, this.paddingRight) as Number;
								
				rectangle.width -= (paddingLeft + paddingRight)
				rectangle.height -= (paddingTop + paddingBottom)
				
				// this takes a few passes for percent-based measurement. we can probably speed it up later
				var availableSpace:Point = reflex.measurement.calculateAvailableSpace(children, rectangle);
				var percentageTotals:Point = reflex.measurement.calculatePercentageTotals(children);
								
				var position:Number = paddingTop;
				var length:int = children.length;
				
				availableSpace.y = gap*(length-1);
				
				var fromTop:Number = 0;
				var measured:Point = this.measure(children);
				switch(verticalAlign) {
					case "center":
					case "middle":
						fromTop = rectangle.height/2 - measured.y/2
						break;
					case "bottom":
						fromTop = rectangle.height - measured.y
						break;
				}
				
				for(var i:int = 0; i < length; i++) {
					var child:Object = children[i];
					var width:Number = reflex.measurement.resolveWidth(child, availableSpace.x, percentageTotals.x); // calculate percentWidths based on full width and with no normalization
					var height:Number = reflex.measurement.resolveHeight(child, availableSpace.y, percentageTotals.y);  // calculate percentHeights based on available height and normalized percentages
					reflex.measurement.setSize(child, Math.round(width), Math.round(height));
					
					switch(horizontalAlign) {
						case "center":
						case "middle":
							child.x = Math.round(rectangle.width/2 - width/2);
							break;
						case "right":
							child.x = Math.round(rectangle.width - width);
							break;
						default:
							child.x = 0;
					}
					child.x += paddingLeft;
					child.y = Math.round(position) + fromTop;
					position += height + gap;
				}
			}
		}
		
	}
}